/**
 *
 * \file LogManager.h
 * \brief LogManager definition class
 * \author Edouard ROGE
 * \date 12 septembre 2010
 *
 */

#ifndef _LOGMANAGER_
#define _LOGMANAGER_

#include <mutex>
#include <vector>
#include "Core/Define/Define.h"
#include "Core/Pattern/Singleton.h"

#if !(defined(__PRETTY_FUNCTION__))
#define __PRETTY_FUNCTION__   __FUNCTION__
#endif

namespace Core
{
	namespace Log
	{
		class Logger;

		/**
		 * \enum eTypeLog
		 * 4 kinds of log type to simplify debugging
		 */
		enum eTypeLog
		{
			/** info log, print information on output */
			eLog_Info = 1 << 0,
			/** warning log, bug may expected */
			eLog_Warning = 1 << 1,
			/** error log, bug expected */
			eLog_Error = 1 << 2,
			/** assert log, critical bug expected */
			eLog_Assert = 1 << 3
		};


		/**
		 * \class LogManager
		 * This class manages log output.
		 * Useful for debugging
		 */
		class LogManager : public Singleton<LogManager>
		{
		public:
			/**
			 * \fn LogManager();
			 * Default constructor
			 */
			LogManager();

			/**
			 * \fn ~LogManager();
			 * Destructor
			 */
			~LogManager();

			/**
			 * \fn void AddLogger( Logger * _pLogger );
			 * \param _pLogger Logger to add and it will be able to write logs to
			 * its output
			 */
			void AddLogger(Logger * _pLogger);

			/**
			 * \fn void RemoveLogger( Logger * _pLogger );
			 * \param _pLogger Logger to remove and no longer available to write logs
			 */
			void RemoveLogger(Logger * _pLogger);

			/**
			 * \fn void Write(const std::string & _filename, const int _nLine, const std::string & _function, const std::string & _strLog, const char * _fmt, ...);
			 * \param _filename Name of the file where the log is
			 * \param _nLine number of the line where the log is
			 * \param _function Name of the function where the log is
			 * \param _strLog log type ("debug", "error", ...)
			 * \param _fmt string format
			 * \param ... arguments
			 * \brief write in logs
			 */
			void Write(const std::string & _filename, const int _nLine, const std::string & _function, const std::string & _strLog, const char * _fmt, ...);

			/**
			 * \fn void Writeline(const std::string & _filename, const int _nLine, const std::string & _function, const std::string & _strLog, const char * _fmt, ...);
			 * \param _filename Name of the file where the log is
			 * \param _nLine number of the line where the log is
			 * \param _function Name of the function where the log is
			 * \param _strLog log type ("debug", "error", ...)
			 * \param _fmt string format
			 * \param ... arguments
			 * \brief write a new line in logs
			 */
			void WriteLine(const std::string & _filename, const int _nLine, const std::string & _function, const std::string & _strLog, const char * _fmt, ...);

			/**
			 * \fn LogManager &	operator << (int32 i);
			 * \param i value to write
			 * \return *this
			 */
			LogManager & operator << (int32 i);

			/**
			 * \fn LogManager &	operator << (uint32 i);
			 * \param i value to write
			 * \return *this
			 */
			LogManager & operator << (uint32 i);

			/**
			 * \fn LogManager &	operator << (float f);
			 * \param f value to write
			 * \return *this
			 */
			LogManager & operator << (float f);

			/**
			 * \fn LogManager &	operator << (double d);
			 * \param d value to write
			 * \return *this
			 */
			LogManager & operator << (double d);

			/**
			 * \fn LogManager &	operator << (char c);
			 * \param c value to write
			 * \return *this
			 */
			LogManager & operator << (char c);

			/**
			 * \fn LogManager &	operator << (char * s);
			 * \param s value to write
			 * \return *this
			 */
			LogManager & operator << (char * s);

			/**
			 * \fn LogManager &	operator << (const char * s);
			 * \param s value to write
			 * \return *this
			 */
			LogManager & operator << (const char * s);

			/**
			 * \fn LogManager &	operator << (void * p);
			 * \param p value to write
			 * \return *this
			 */
			LogManager & operator << (void * p);

			/**
			 * \fn LogManager &	operator << (const void * p);
			 * \param p value to write
			 * \return *this
			 */
			LogManager & operator << (const void * p);

			/**
			 * \fn void AddFlags(uint32 _iFlags);
			 * \param _iFlags Flag to add
			 */
			void AddFlags(uint32 _iFlags);

			/**
			 * \fn bool IsFlagActive(uint32 _iFlag) const;
			 * \param _iFlag value to test
			 * \return true if _iFlag is activated
			 */
			bool IsFlagActive(uint32 _iFlag) const;

		private:

			/** list of activated flag */
			uint32					m_iFlags;

			/** vector of loggers, if a logger is present, it will be able to log in its output */
			std::vector< Logger * >	m_vpLogger;

			/** Mutex */
			std::mutex m_mutex;
		};

	}
}

/**
 * if eLog_Info flag is activated
 * log in loggers and trigger an assert
 * manage variadic arguments ("%d %f %s %c")
 */
#define LOG_INFO( ... )		if( Core::Log::LogManager::GetInstance().IsFlagActive( Core::Log::eLog_Info ) )\
							{\
								Core::Log::LogManager::GetInstance().WriteLine(__FILE__, __LINE__, __PRETTY_FUNCTION__, "[INFO] ", __VA_ARGS__); \
							}

/**
 * if eLog_Info flag is activated
 * log in loggers and trigger an assert
 * manage variadic arguments ("%d %f %s %c")
 */
#define LOG_WARNING( ... )	if( Core::Log::LogManager::GetInstance().IsFlagActive( Core::Log::eLog_Warning ) )\
							{\
								Core::Log::LogManager::GetInstance().WriteLine(__FILE__, __LINE__, __PRETTY_FUNCTION__, "[WARNING] ", __VA_ARGS__); \
							}

/**
 * if eLog_Info flag is activated
 * log in loggers and trigger an assert
 * manage variadic arguments ("%d %f %s %c")
 */
#define LOG_ERROR( ... )	if( Core::Log::LogManager::GetInstance().IsFlagActive( Core::Log::eLog_Error ) )\
							{\
								Core::Log::LogManager::GetInstance().WriteLine(__FILE__, __LINE__, __PRETTY_FUNCTION__, "[ERROR] ", __VA_ARGS__); \
							}

/**
 * if eLog_Assert flag is activated
 * log in loggers and trigger an assert
 * manage variadic arguments ("%d %f %s %c")
 */
#define LOG_ASSERT( expr, ... )	if( Core::Log::LogManager::GetInstance().IsFlagActive( Core::Log::eLog_Assert ) && !(expr) )\
								{\
									Core::Log::LogManager::GetInstance().WriteLine(__FILE__, __LINE__, __PRETTY_FUNCTION__, "[ASSERT] ", __VA_ARGS__); \
								}

#endif // _LOGMANAGER_
